package org.yakindu.scr.digitalwatch;
import org.yakindu.scr.TimeEvent;
import org.yakindu.scr.ITimerService;

public class DigitalwatchStatemachine implements IDigitalwatchStatemachine {

	private final TimeEvent digitalwatch_main_region_test_case_addTime_addTime_time_event_0 = new TimeEvent(
			false, 0);
	private final TimeEvent digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0 = new TimeEvent(
			false, 1);
	private final TimeEvent digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0 = new TimeEvent(
			false, 2);
	private final TimeEvent digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0 = new TimeEvent(
			false, 3);
	private final TimeEvent digitalwatch_main_region_test_case_light_lightTimer_time_event_0 = new TimeEvent(
			false, 4);

	private final boolean[] timeEvents = new boolean[5];

	private final class SCIButtonsImpl implements SCIButtons {

		private boolean topLeftPressed;

		public void raiseTopLeftPressed() {
			topLeftPressed = true;
		}

		private boolean topLeftReleased;

		public void raiseTopLeftReleased() {
			topLeftReleased = true;
		}

		private boolean topRightPressed;

		public void raiseTopRightPressed() {
			topRightPressed = true;
		}

		private boolean topRightReleased;

		public void raiseTopRightReleased() {
			topRightReleased = true;
		}

		private boolean bottomLeftPressed;

		public void raiseBottomLeftPressed() {
			bottomLeftPressed = true;
		}

		private boolean bottomLeftReleased;

		public void raiseBottomLeftReleased() {
			bottomLeftReleased = true;
		}

		private boolean bottomRightPressed;

		public void raiseBottomRightPressed() {
			bottomRightPressed = true;
		}

		private boolean bottomRightReleased;

		public void raiseBottomRightReleased() {
			bottomRightReleased = true;
		}

		public void clearEvents() {
			topLeftPressed = false;
			topLeftReleased = false;
			topRightPressed = false;
			topRightReleased = false;
			bottomLeftPressed = false;
			bottomLeftReleased = false;
			bottomRightPressed = false;
			bottomRightReleased = false;
		}

	}

	private SCIButtonsImpl sCIButtons;
	private final class SCIDisplayImpl implements SCIDisplay {

		private SCIDisplayOperationCallback operationCallback;

		public void setSCIDisplayOperationCallback(
				SCIDisplayOperationCallback operationCallback) {
			this.operationCallback = operationCallback;
		}

	}

	private SCIDisplayImpl sCIDisplay;
	private final class SCILogicUnitImpl implements SCILogicUnit {

		private SCILogicUnitOperationCallback operationCallback;

		public void setSCILogicUnitOperationCallback(
				SCILogicUnitOperationCallback operationCallback) {
			this.operationCallback = operationCallback;
		}

		private boolean startAlarm;

		public void raiseStartAlarm() {
			startAlarm = true;
		}

		public void clearEvents() {
			startAlarm = false;
		}

	}

	private SCILogicUnitImpl sCILogicUnit;

	public enum State {
		main_region_test_case, main_region_test_case_addTime_addTime, main_region_test_case_ChronoTimer_chrono, main_region_test_case_ChronoTimer_addTime, main_region_test_case_refreshDisplay_TimeDisplay, main_region_test_case_refreshDisplay_ChronoDisplay, main_region_test_case_refreshDisplay_startChrono, main_region_test_case_refreshDisplay_stopChrono, main_region_test_case_light_lightOff, main_region_test_case_light_lightOn, main_region_test_case_light_lightTimer, $NullState$
	};

	private boolean chronoRunning;

	private final State[] stateVector = new State[4];

	private int nextStateIndex;

	private ITimerService timerService;

	private long cycleStartTime;

	public DigitalwatchStatemachine() {

		sCIButtons = new SCIButtonsImpl();
		sCIDisplay = new SCIDisplayImpl();
		sCILogicUnit = new SCILogicUnitImpl();

		digitalwatch_main_region_test_case_addTime_addTime_time_event_0
				.setStatemachine(this);
		digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0
				.setStatemachine(this);
		digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0
				.setStatemachine(this);
		digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0
				.setStatemachine(this);
		digitalwatch_main_region_test_case_light_lightTimer_time_event_0
				.setStatemachine(this);
	}

	public void init() {
		if (timerService == null) {
			throw new IllegalStateException("TimerService not set.");
		}
		for (int i = 0; i < 4; i++) {
			stateVector[i] = State.$NullState$;
		}

		clearEvents();
		clearOutEvents();

		chronoRunning = false;
	}

	public void enter() {
		if (timerService == null) {
			throw new IllegalStateException("TimerService not set.");
		}
		cycleStartTime = timerService.getSystemTimeMillis();
		entryAction();

		getTimerService()
				.setTimer(
						digitalwatch_main_region_test_case_addTime_addTime_time_event_0,
						1 * 1000, cycleStartTime);

		sCILogicUnit.operationCallback.increaseTimeByOne();

		nextStateIndex = 0;
		stateVector[0] = State.main_region_test_case_addTime_addTime;

		nextStateIndex = 1;
		stateVector[1] = State.main_region_test_case_ChronoTimer_chrono;

		getTimerService()
				.setTimer(
						digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0,
						1 * 1000, cycleStartTime);

		sCIDisplay.operationCallback.refreshTimeDisplay();

		sCIDisplay.operationCallback.refreshDateDisplay();

		nextStateIndex = 2;
		stateVector[2] = State.main_region_test_case_refreshDisplay_TimeDisplay;

		sCIDisplay.operationCallback.unsetIndiglo();

		nextStateIndex = 3;
		stateVector[3] = State.main_region_test_case_light_lightOff;
	}

	public void exit() {
		switch (stateVector[0]) {
			case main_region_test_case_addTime_addTime :
				nextStateIndex = 0;
				stateVector[0] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_addTime_addTime_time_event_0);
				break;

			default :
				break;
		}

		switch (stateVector[1]) {
			case main_region_test_case_ChronoTimer_chrono :
				nextStateIndex = 1;
				stateVector[1] = State.$NullState$;
				break;

			case main_region_test_case_ChronoTimer_addTime :
				nextStateIndex = 1;
				stateVector[1] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0);
				break;

			default :
				break;
		}

		switch (stateVector[2]) {
			case main_region_test_case_refreshDisplay_TimeDisplay :
				nextStateIndex = 2;
				stateVector[2] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0);
				break;

			case main_region_test_case_refreshDisplay_ChronoDisplay :
				nextStateIndex = 2;
				stateVector[2] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0);
				break;

			case main_region_test_case_refreshDisplay_startChrono :
				nextStateIndex = 2;
				stateVector[2] = State.$NullState$;
				break;

			case main_region_test_case_refreshDisplay_stopChrono :
				nextStateIndex = 2;
				stateVector[2] = State.$NullState$;
				break;

			default :
				break;
		}

		switch (stateVector[3]) {
			case main_region_test_case_light_lightOff :
				nextStateIndex = 3;
				stateVector[3] = State.$NullState$;
				break;

			case main_region_test_case_light_lightOn :
				nextStateIndex = 3;
				stateVector[3] = State.$NullState$;
				break;

			case main_region_test_case_light_lightTimer :
				nextStateIndex = 3;
				stateVector[3] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_light_lightTimer_time_event_0);
				break;

			default :
				break;
		}

		exitAction();
	}

	protected void clearEvents() {
		sCIButtons.clearEvents();
		sCILogicUnit.clearEvents();

		for (int i = 0; i < timeEvents.length; i++) {
			timeEvents[i] = false;
		}
	}

	protected void clearOutEvents() {
	}

	public boolean isStateActive(State state) {
		switch (state) {
			case main_region_test_case :
				return stateVector[0].ordinal() >= State.main_region_test_case
						.ordinal()
						&& stateVector[0].ordinal() <= State.main_region_test_case_light_lightTimer
								.ordinal();
			case main_region_test_case_addTime_addTime :
				return stateVector[0] == State.main_region_test_case_addTime_addTime;
			case main_region_test_case_ChronoTimer_chrono :
				return stateVector[1] == State.main_region_test_case_ChronoTimer_chrono;
			case main_region_test_case_ChronoTimer_addTime :
				return stateVector[1] == State.main_region_test_case_ChronoTimer_addTime;
			case main_region_test_case_refreshDisplay_TimeDisplay :
				return stateVector[2] == State.main_region_test_case_refreshDisplay_TimeDisplay;
			case main_region_test_case_refreshDisplay_ChronoDisplay :
				return stateVector[2] == State.main_region_test_case_refreshDisplay_ChronoDisplay;
			case main_region_test_case_refreshDisplay_startChrono :
				return stateVector[2] == State.main_region_test_case_refreshDisplay_startChrono;
			case main_region_test_case_refreshDisplay_stopChrono :
				return stateVector[2] == State.main_region_test_case_refreshDisplay_stopChrono;
			case main_region_test_case_light_lightOff :
				return stateVector[3] == State.main_region_test_case_light_lightOff;
			case main_region_test_case_light_lightOn :
				return stateVector[3] == State.main_region_test_case_light_lightOn;
			case main_region_test_case_light_lightTimer :
				return stateVector[3] == State.main_region_test_case_light_lightTimer;
			default :
				return false;
		}
	}

	public void setTimerService(ITimerService timerService) {
		this.timerService = timerService;
	}

	public ITimerService getTimerService() {
		return timerService;
	}

	public void onTimeEventRaised(TimeEvent timeEvent) {
		timeEvents[timeEvent.getIndex()] = true;
	}

	public SCIButtons getSCIButtons() {
		return sCIButtons;
	}
	public SCIDisplay getSCIDisplay() {
		return sCIDisplay;
	}
	public SCILogicUnit getSCILogicUnit() {
		return sCILogicUnit;
	}

	/* Entry action for statechart 'digitalwatch'. */
	private void entryAction() {
	}

	/* Exit action for state 'digitalwatch'. */
	private void exitAction() {
	}

	/* The reactions of state addTime. */
	private void reactMain_region_test_case_addTime_addTime() {
		if (timeEvents[digitalwatch_main_region_test_case_addTime_addTime_time_event_0
				.getIndex()]) {
			nextStateIndex = 0;
			stateVector[0] = State.$NullState$;

			getTimerService()
					.resetTimer(
							digitalwatch_main_region_test_case_addTime_addTime_time_event_0);

			getTimerService()
					.setTimer(
							digitalwatch_main_region_test_case_addTime_addTime_time_event_0,
							1 * 1000, cycleStartTime);

			sCILogicUnit.operationCallback.increaseTimeByOne();

			nextStateIndex = 0;
			stateVector[0] = State.main_region_test_case_addTime_addTime;
		}
	}

	/* The reactions of state chrono. */
	private void reactMain_region_test_case_ChronoTimer_chrono() {
		if (chronoRunning == true) {
			nextStateIndex = 1;
			stateVector[1] = State.$NullState$;

			getTimerService()
					.setTimer(
							digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0,
							10, cycleStartTime);

			sCILogicUnit.operationCallback.increaseChronoByOne();

			nextStateIndex = 1;
			stateVector[1] = State.main_region_test_case_ChronoTimer_addTime;
		}
	}

	/* The reactions of state addTime. */
	private void reactMain_region_test_case_ChronoTimer_addTime() {
		if (timeEvents[digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0
				.getIndex()]) {
			nextStateIndex = 1;
			stateVector[1] = State.$NullState$;

			getTimerService()
					.resetTimer(
							digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0);

			getTimerService()
					.setTimer(
							digitalwatch_main_region_test_case_ChronoTimer_addTime_time_event_0,
							10, cycleStartTime);

			sCILogicUnit.operationCallback.increaseChronoByOne();

			nextStateIndex = 1;
			stateVector[1] = State.main_region_test_case_ChronoTimer_addTime;
		}
	}

	/* The reactions of state TimeDisplay. */
	private void reactMain_region_test_case_refreshDisplay_TimeDisplay() {
		if (timeEvents[digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0
				.getIndex()]) {
			nextStateIndex = 2;
			stateVector[2] = State.$NullState$;

			getTimerService()
					.resetTimer(
							digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0);

			getTimerService()
					.setTimer(
							digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0,
							1 * 1000, cycleStartTime);

			sCIDisplay.operationCallback.refreshTimeDisplay();

			sCIDisplay.operationCallback.refreshDateDisplay();

			nextStateIndex = 2;
			stateVector[2] = State.main_region_test_case_refreshDisplay_TimeDisplay;
		} else {
			if (sCIButtons.topLeftPressed) {
				nextStateIndex = 2;
				stateVector[2] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0);

				getTimerService()
						.setTimer(
								digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0,
								10, cycleStartTime);

				sCIDisplay.operationCallback.refreshChronoDisplay();

				nextStateIndex = 2;
				stateVector[2] = State.main_region_test_case_refreshDisplay_ChronoDisplay;
			}
		}
	}

	/* The reactions of state ChronoDisplay. */
	private void reactMain_region_test_case_refreshDisplay_ChronoDisplay() {
		if (timeEvents[digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0
				.getIndex()]) {
			nextStateIndex = 2;
			stateVector[2] = State.$NullState$;

			getTimerService()
					.resetTimer(
							digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0);

			getTimerService()
					.setTimer(
							digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0,
							10, cycleStartTime);

			sCIDisplay.operationCallback.refreshChronoDisplay();

			nextStateIndex = 2;
			stateVector[2] = State.main_region_test_case_refreshDisplay_ChronoDisplay;
		} else {
			if (sCIButtons.topLeftPressed) {
				nextStateIndex = 2;
				stateVector[2] = State.$NullState$;

				getTimerService()
						.resetTimer(
								digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0);

				getTimerService()
						.setTimer(
								digitalwatch_main_region_test_case_refreshDisplay_TimeDisplay_time_event_0,
								1 * 1000, cycleStartTime);

				sCIDisplay.operationCallback.refreshTimeDisplay();

				sCIDisplay.operationCallback.refreshDateDisplay();

				nextStateIndex = 2;
				stateVector[2] = State.main_region_test_case_refreshDisplay_TimeDisplay;
			} else {
				if (sCIButtons.bottomRightPressed) {
					nextStateIndex = 2;
					stateVector[2] = State.$NullState$;

					getTimerService()
							.resetTimer(
									digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0);

					if (chronoRunning == false) {
						chronoRunning = true;

						nextStateIndex = 2;
						stateVector[2] = State.main_region_test_case_refreshDisplay_startChrono;
					} else {
						chronoRunning = false;

						nextStateIndex = 2;
						stateVector[2] = State.main_region_test_case_refreshDisplay_stopChrono;
					}
				}
			}
		}
	}

	/* The reactions of state startChrono. */
	private void reactMain_region_test_case_refreshDisplay_startChrono() {
		nextStateIndex = 2;
		stateVector[2] = State.$NullState$;

		getTimerService()
				.setTimer(
						digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0,
						10, cycleStartTime);

		sCIDisplay.operationCallback.refreshChronoDisplay();

		nextStateIndex = 2;
		stateVector[2] = State.main_region_test_case_refreshDisplay_ChronoDisplay;
	}

	/* The reactions of state stopChrono. */
	private void reactMain_region_test_case_refreshDisplay_stopChrono() {
		nextStateIndex = 2;
		stateVector[2] = State.$NullState$;

		getTimerService()
				.setTimer(
						digitalwatch_main_region_test_case_refreshDisplay_ChronoDisplay_time_event_0,
						10, cycleStartTime);

		sCIDisplay.operationCallback.refreshChronoDisplay();

		nextStateIndex = 2;
		stateVector[2] = State.main_region_test_case_refreshDisplay_ChronoDisplay;
	}

	/* The reactions of state lightOff. */
	private void reactMain_region_test_case_light_lightOff() {
		if (sCIButtons.topRightPressed) {
			nextStateIndex = 3;
			stateVector[3] = State.$NullState$;

			sCIDisplay.operationCallback.setIndiglo();

			nextStateIndex = 3;
			stateVector[3] = State.main_region_test_case_light_lightOn;
		}
	}

	/* The reactions of state lightOn. */
	private void reactMain_region_test_case_light_lightOn() {
		if (sCIButtons.topRightReleased) {
			nextStateIndex = 3;
			stateVector[3] = State.$NullState$;

			getTimerService()
					.setTimer(
							digitalwatch_main_region_test_case_light_lightTimer_time_event_0,
							2 * 1000, cycleStartTime);

			nextStateIndex = 3;
			stateVector[3] = State.main_region_test_case_light_lightTimer;
		}
	}

	/* The reactions of state lightTimer. */
	private void reactMain_region_test_case_light_lightTimer() {
		if (timeEvents[digitalwatch_main_region_test_case_light_lightTimer_time_event_0
				.getIndex()]) {
			nextStateIndex = 3;
			stateVector[3] = State.$NullState$;

			getTimerService()
					.resetTimer(
							digitalwatch_main_region_test_case_light_lightTimer_time_event_0);

			sCIDisplay.operationCallback.unsetIndiglo();

			nextStateIndex = 3;
			stateVector[3] = State.main_region_test_case_light_lightOff;
		}
	}

	public void runCycle() {

		cycleStartTime = timerService.getSystemTimeMillis();

		clearOutEvents();

		for (nextStateIndex = 0; nextStateIndex < stateVector.length; nextStateIndex++) {

			switch (stateVector[nextStateIndex]) {
				case main_region_test_case_addTime_addTime :
					reactMain_region_test_case_addTime_addTime();
					break;
				case main_region_test_case_ChronoTimer_chrono :
					reactMain_region_test_case_ChronoTimer_chrono();
					break;
				case main_region_test_case_ChronoTimer_addTime :
					reactMain_region_test_case_ChronoTimer_addTime();
					break;
				case main_region_test_case_refreshDisplay_TimeDisplay :
					reactMain_region_test_case_refreshDisplay_TimeDisplay();
					break;
				case main_region_test_case_refreshDisplay_ChronoDisplay :
					reactMain_region_test_case_refreshDisplay_ChronoDisplay();
					break;
				case main_region_test_case_refreshDisplay_startChrono :
					reactMain_region_test_case_refreshDisplay_startChrono();
					break;
				case main_region_test_case_refreshDisplay_stopChrono :
					reactMain_region_test_case_refreshDisplay_stopChrono();
					break;
				case main_region_test_case_light_lightOff :
					reactMain_region_test_case_light_lightOff();
					break;
				case main_region_test_case_light_lightOn :
					reactMain_region_test_case_light_lightOn();
					break;
				case main_region_test_case_light_lightTimer :
					reactMain_region_test_case_light_lightTimer();
					break;
				default :
					// $NullState$
			}
		}

		clearEvents();
	}
}
